home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 December / MACPOWER-1997-12.ISO.7z / MACPOWER-1997-12.ISO / AMUG / PROGRAMMING / Raven 1.2.sit / Raven 1.2 / Source / Foundation / Common / ZFixedAllocator.cpp < prev    next >
Text File  |  1997-07-13  |  5KB  |  208 lines

  1. /*
  2.  *  File:       ZFixedAllocator.cpp
  3.  *  Summary:    A class that can speedily allocate fixed size blocks.
  4.  *  Written by: Jesse Jones
  5.  *
  6.  *  Copyright ゥ 1997 Jesse Jones. 
  7.  *    For conditions of distribution and use, see copyright notice in ZTypes.h  
  8.  *
  9.  *  Change History (most recent first):
  10.  *
  11.  *         <2>     7/13/97    JDJ        Inlined HasBlock.
  12.  *         <1>     1/29/96    JDJ        Created
  13.  */
  14.  
  15. #include <ZFixedAllocator.h>
  16.  
  17. #include <ZDebug.h>
  18. #include <ZExceptions.h>
  19.  
  20. #if DEBUG
  21. #include <ZMemUtils.h>
  22. #endif
  23.  
  24.  
  25. // ===================================================================================
  26. //    struct SBlock
  27. //        This is a variable length struct. If the block is free the first four bytes
  28. //        are a pointer to the next free block. Otherwise the contents are the user data.
  29. // ===================================================================================
  30. struct SBlock {
  31.     SBlock*    nextFree;
  32. };
  33.  
  34.  
  35. // ===================================================================================
  36. //    class TFixedAllocator
  37. // ===================================================================================
  38.  
  39. //---------------------------------------------------------------
  40. //
  41. // TFixedAllocator::~TFixedAllocator
  42. //
  43. //---------------------------------------------------------------
  44. TFixedAllocator::~TFixedAllocator()
  45. {
  46.     DisposePtr((Ptr) mBlocks);
  47. }
  48.  
  49.  
  50. //---------------------------------------------------------------
  51. //
  52. // TFixedAllocator::TFixedAllocator
  53. //
  54. //---------------------------------------------------------------
  55. TFixedAllocator::TFixedAllocator(ulong blockSize, ulong maxBlocks)
  56. {
  57.     ASSERT(blockSize >= sizeof(SBlock));
  58.     ASSERT(maxBlocks > 0);
  59.     ASSERT(blockSize*maxBlocks < 4*1024L*1024L);
  60.     
  61.     mBlockSize = blockSize;
  62.     mMaxBlocks = maxBlocks;
  63.     
  64.     mBlocks = reinterpret_cast<SBlock*>(NewPtr(mBlockSize*mMaxBlocks));
  65.     ThrowIfNil(mBlocks);
  66.     
  67.     mBlockCount    = 0;
  68.     mMaxBlockCount = 0;
  69.     
  70.     mNextFreeBlock = mBlocks;
  71.     mEndBlock      = reinterpret_cast<SBlock*>((char*) mBlocks + mBlockSize*mMaxBlocks);
  72.     
  73.     // Link all the blocks up.
  74.     SBlock* block = mNextFreeBlock;
  75.     while (block != nil) {
  76.         SBlock* next = this->GetNextBlock(block);
  77.         
  78.         block->nextFree = next;
  79.         
  80.         block = next;
  81.     }
  82. }
  83.  
  84.  
  85. //---------------------------------------------------------------
  86. //
  87. // TFixedAllocator::Allocate
  88. //
  89. //---------------------------------------------------------------
  90. void* TFixedAllocator::Allocate()
  91. {
  92.     ASSERT(mBlockCount <= mMaxBlockCount);
  93.     ASSERT(mBlockCount <= mMaxBlocks);
  94.     ASSERT((mNextFreeBlock == nil) == (mBlockCount == mMaxBlocks));
  95.  
  96.     void* ptr = nil;
  97.     
  98.     if (mNextFreeBlock != nil) {
  99.         SBlock* next = mNextFreeBlock->nextFree;
  100.         
  101.         ptr = mNextFreeBlock;
  102.         
  103.         mNextFreeBlock = next;
  104.         mBlockCount++;
  105.         
  106.         if (mBlockCount > mMaxBlockCount)
  107.             mMaxBlockCount = mBlockCount;
  108.     }
  109.     
  110.     return ptr;
  111. }
  112.  
  113.  
  114. //---------------------------------------------------------------
  115. //
  116. // TFixedAllocator::Deallocate
  117. //
  118. //---------------------------------------------------------------
  119. void TFixedAllocator::Deallocate(void* ptr)
  120. {
  121.     if (ptr != nil) {
  122.         SBlock* block = reinterpret_cast<SBlock*>(ptr);
  123.         
  124.         ASSERT(block >= mBlocks);
  125.         ASSERT(block < mEndBlock);
  126.         
  127.         block->nextFree = mNextFreeBlock;            
  128.         mNextFreeBlock = block;
  129.  
  130.         mBlockCount--;
  131.     }
  132. }
  133.  
  134.  
  135. //---------------------------------------------------------------
  136. //
  137. // TFixedAllocator::ValidateHeap
  138. //
  139. //---------------------------------------------------------------
  140. #if DEBUG
  141. void TFixedAllocator::ValidateHeap(BlockValidateHook hook, void* refCon) const
  142. {
  143.     ASSERT(mBlockSize >= sizeof(SBlock));
  144.     ASSERT(mBlocks != nil);
  145.     ASSERT(mMaxBlocks > 0);
  146.     ASSERT(mMaxBlockCount <= mMaxBlocks);
  147.     ASSERT(mBlockCount <= mMaxBlockCount);
  148.     ASSERT(mEndBlock == reinterpret_cast<SBlock*>((char*) mBlocks + mBlockSize*mMaxBlocks));
  149.     ASSERT((mNextFreeBlock == nil) == (mBlockCount == mMaxBlocks));
  150.     ASSERT(mNextFreeBlock == nil || (mNextFreeBlock >= mBlocks && mNextFreeBlock < mEndBlock));
  151.     
  152.     if (hook != nil) {
  153.         Boolean** inUse = reinterpret_cast<Boolean**>(NewHandle(mMaxBlocks));    // use Boolean since sizeof(bool) may be more than one byte
  154.         if (inUse != nil) {
  155.             // Mark all the blocks as in use.
  156.             SetMemory(*inUse, true, mMaxBlocks);            
  157.         
  158.             // Find out which blocks are not in use.
  159.             const SBlock* block = mNextFreeBlock;
  160.             while (block != nil) {
  161.                 ulong index = ((char*) block - (char*) mBlocks)/mBlockSize;        // can't use straight pointer arithmetic since SBlock is variable length
  162.                 ASSERT(index < mMaxBlocks);
  163.                 
  164.                 (*inUse)[index] = false;
  165.                 
  166.                 block = block->nextFree;
  167.             }
  168.             
  169.             // Call the validate hook for each block in use.
  170.             for (ulong index = 0; index < mMaxBlocks; index++) {
  171.                 if ((*inUse)[index]) {
  172.                     block = reinterpret_cast<const SBlock*>((char*) mBlocks + index*mBlockSize);
  173.                     ASSERT(block < mEndBlock);
  174.                 
  175.                     (*hook)(block, (long) mBlockSize, refCon);
  176.                 }
  177.             }
  178.             
  179.             DisposeHandle((Handle) inUse);
  180.     
  181.         } else
  182.             DEBUGSTR("Not enough free memory for TFixedAllocator::ValidateHeap");
  183.     }
  184. }
  185. #endif
  186.  
  187.  
  188. //---------------------------------------------------------------
  189. //
  190. // TFixedAllocator::GetNextBlock
  191. //
  192. //---------------------------------------------------------------
  193. SBlock* TFixedAllocator::GetNextBlock(SBlock* block) const
  194. {
  195.     ASSERT(block != nil);
  196.     ASSERT(block >= mBlocks);
  197.     
  198.     block = reinterpret_cast<SBlock*>((char*) block + mBlockSize);
  199.     
  200.     if (block >= mEndBlock)
  201.         block = nil;
  202.         
  203.     return block;
  204. }
  205.  
  206.  
  207.  
  208.